# 1.4 jfinal-undertow 高级用法
# 一、基础配置
# 1、启用配置文件
在 src/main/resources 目录下面创建 undertow.txt 文件,该文件会被 jfinal undertow 自动加载并对 jfinal undertow 进行配置。
如果不想使用 "undertow.txt" 这个文件名,还可以通过 UndertowServer.create(AppConfig.class, "other.txt") 方法的第二个参数来指定自己喜欢的文件名。
配置文件创建好以后,就可以按照下面的文档来配置相应的功能了。
# 2、常用配置
# true 值支持热加载
undertow.devMode=true
undertow.port=80
undertow.host=0.0.0.0
# 绝大部分情况不建议配置 context path
undertow.contextPath=/abc
2
3
4
5
6
7
开发时配置成 true 支持热加载,注意该 devMode 与 jfinal 项目中的 devMode 没有任何关系,注意区分。
重要:老版本的 undertow.host 配置的默认值为 localhost,Linux 操作系统下的安全设置可能无法在外网访问 localhost 下部署的项目,修改配置 undertow.host=0.0.0.0 即可。如果使用了 nginx 做了代理,可保持 localhost 配置。
# 3、web 资源加载路径配置
jfinal undertow 可以十分方便地从文件系统的目录以及 class path 或 jar 包中加载 web 静态资源,以下是配置示例:
undertow.resourcePath = src/main/webapp, classpath:static
如上所示 "src/main/webapp" 表示从项目根目录下的 "src/main/webapp" 下去加载 web 静态资源。 "classpath:static" 表示从 class path 以及 jar 包中的 static 路径下去加载 web 静态资源。
注意:"classpath:static" 这种配置是 jfinal undertow 1.5 才添加的功能。
undertow.resourcePath 配置的另一个重点是,以 "classpath:" 为前缀的配置需要自行注意路径是否存在,尽可能只配置存在的路径。而不以 "classpath:" 打头的配置可以将开发与部署时的路径一起配置进来(逗号分隔开),jfinal undertow 会在运行时检测路径是否存在,存在才真正让其生效,从而很方便一次配置同时适用于开发、生产两种环境。
重要:PathKit.getWebRootPath() 将指向 undertow.resourcePath 配置中的第一个有效目录,而 configEngine(Engine engine) 方法中的 engine 对象已被默认配置了 engine.setBaseTemplatePath(PathKit.getWebRootPath())。所以该配置与 engine 的 baseTemplatePath 有关联。
# 4、性能配置
# io 线程数与 worker 线程数
# undertow.ioThreads=
# undertow.workerThreads=
2
3
默认配置已充分考虑常用场景,如果没有压测数据作为指导,建议使用默认配置,不要添加这两项配置。
ioThreads 为 NIO 处理 io 请求的线程数量,在生产环境下建议的配置范围是 cpu 核心数的一倍到两倍。建议根据压测结果进行调整。
workerThreads 是处理请求的线程数量,在生产环境下可以使用默认配置,或者根据压测结果进行配置。在压测数据几乎最好的情况下尽可能选择更小的 workThreads 值。因为当性能达到某个高度时再增加 workThreads 值并不会带来性能提升,但会增加系统的资源消耗。
# 5、开启 gzip 压缩
# gzip 压缩开关
undertow.gzip.enable=true
# 配置压缩级别,默认值 -1。 可配置 1 到 9。 1 拥有最快压缩速度,9 拥有最高压缩率
undertow.gzip.level=-1
# 触发压缩的最小内容长度
undertow.gzip.minLength=1024
2
3
4
5
6
开启 gzip 压缩可以降低网络流量,提升访问速度
# 6、配置 session
# session 过期时间,注意单位是秒
undertow.session.timeout=1800
# 支持 session 热加载,避免依赖于 session 的登录型项目反复登录,默认值为 true。仅用于 devMode,生产环境无影响
undertow.session.hotSwap=true
2
3
4
# 7、配置 https
# 是否开启 ssl
undertow.ssl.enable=false
# ssl 监听端口号,部署环境设置为 443
undertow.ssl.port=443
# 密钥库类型,建议使用 PKCS12
undertow.ssl.keyStoreType=PKCS12
# 密钥库文件
undertow.ssl.keyStore=demo.pfx
# 密钥库密码
undertow.ssl.keyStorePassword=123456
# 别名配置,一般不使用
undertow.ssl.keyAlias=demo
SSL 证书的获取见后面的第二小节
2
3
4
5
6
7
8
9
10
11
12
13
# 8、配置 http2
# ssl 开启时,是否开启 http2。检测该配置是否生效在 chrome 地址栏中输入: chrome://net-internals/#http2
undertow.http2.enable=true
2
开启 http2 可以大大加快访问速度,不必担心 https 比 http 慢这个事
# 9、配置 http 重定向到 https
# ssl 开启时,http 请求是否重定向到 https
undertow.http.toHttps=false
# ssl 开启时,http 请求跳转到 https 使用的状态码,默认值 302
undertow.http.toHttpsStatusCode=302
### 10、配置关闭 http
# ssl 开启时,是否关闭 http
undertow.http.disable=false
2
3
4
5
6
7
在启用 https 后,可以配置关闭 http,这样就只能访问 https 了。该配置项比较适合于小程序服务端。
对于一般的 web 项目不建议配置此项,而是配置 undertow.http.toHttps=true 将 http 重定向到 https
# 11、自由配置 Undertow
以上配置方式由 jfinal undertow 做了直接的支持,如果上面的配置仍然不能满足需求,还可以通过下面的方式自由配置 undertow:
UndertowServer.create(YourJFinalConfig.class)
.onStart( builder -> {
builder.setServerOption(UndertowOptions.参数名, 参数值);
})
.start();
2
3
4
5
如上所示,通过在 onStart 方法中使用 builder.setServerOption(...) 可以对 underow 进行更加深入的配置,还可以调用 builder 中的其它 API 进行其它类型的配置。上述的 UndertowOptions 中定义了很多 undertow 的配置名,查看其中的注释文档可以知道还有很多有用的配置
# 12、添加 Filter、WebSocket、Servlet、Listener
特别注意,Undertow 是为嵌入而生的 Web Server,web.xml 已被抛弃,所以无法通过 web.xml 配置 web 组件。
为此 jfinal undertow 提供了 UndertowServer.configWeb(...) 可以很方便添加 Filter、WebSocket、Servlet、Listener 这些标准的 Java Web 组件:
UndertowServer.create(AppConfig.class)
.configWeb( builder -> {
// 配置 Filter
builder.addFilter("myFilter", "com.abc.MyFilter");
builder.addFilterUrlMapping("myFilter", "/*");
builder.addFilterInitParam("myFilter", "key", "value");
// 配置 Servlet
builder.addServlet("myServlet", "com.abc.MyServlet");
builder.addServletMapping("myServlet", "*.do");
builder.addServletInitParam("myServlet", "key", "value");
// 配置 Listener
builder.addListener("com.abc.MyListener");
// 配置 WebSocket,MyWebSocket 需使用 ServerEndpoint 注解
builder.addWebSocketEndpoint("com.abc.MyWebSocket");
})
.start();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
注意,JFinalFilter 会接管所有请求,所以上面代码中 addServletMapping(...) 映射的 servlet 默认是无法被请求到的,需要在 configHandler(Handlers me) 中配置 UrlSkipHandler 让 jfinal 跳过这些 serlvet 的 url
以上代码中的 MyWebSocket 需要使用 ServerEndpoint 注解标识其为一个 WebSocket 组件,例如:
@ServerEndpoint("/myapp.ws")
public class MyWebSocket {
@OnMessage
public void message(String message, Session session) {
for (Session s : session.getOpenSessions()) {
s.getAsyncRemote().sendText(message);
}
}
}
2
3
4
5
6
7
8
9
与上述 MyWebSocket 配合使用的例子 html 在这里可以下载:传送门。社区同学分享的完整 websocket 代码在这里:https://jfinal.com/share/2004
要修改一下该 html 中的 url 为: "ws://localhost:80/myapp.ws",端口号适当调整。
注意:由于 JFinalFilter 会接管所有不带 "." 字符的 URL 请求所以 @ServerEndpoint 注解中的 URL 参数值建议以 ".ws" 结尾,否则请求会响应 404 找不到资源,例如:
@ServerEndpoint("/myapp.ws")
public class MyWebSocketEndpoint {
......
}
2
3
4
当然,ServerEndpoint 中的 URL 不使用 ".ws" 结尾也是可以的,只需要参考 jfinal 的 UrlSkipHandler 做一个 Handler 跳过属于 WebSocket 的 URL 即可
最后,websocket 支持需要添加一个依赖,要添加的依赖项请看前面的文档:https://jfinal.com/doc/1-2
# 二、SSL 证书
# 1、申请 SSL 证书
建议从阿里云或者腾迅云获取 SSL 证书,有免费版和收费版,阿里云 SSL 证书获取:SSL 证书获取传送门
注意:在申请免费版 SSL 证书的过程中,绑定域名一般输入主机名为 www 的域名,例如: www.jfinal.com
# 2、下载合适的证书类型
SSL 证书申请下来以后,可以到控制台下载证书,如下图所示:
点击下载链接以后,在右侧下载 tomcat 类型的 SSL 证书
下载的证书里头,有一个 xxx.pfx 文件,该文件就是证书文件。此外还有一个 pfx-password.txt 文件,此文件里面放的是证书密码,将 xxx.pfx 放入项目的 src/main/resources 目录,在 undertow.txt 配置文件中添加如下几行配置:
# 是否开启 ssl
undertow.ssl.enable=true
# ssl 监听端口号,部署环境设置为 443
undertow.ssl.port=443
# 密钥库类型,一般是 PKCS12 与 JKS,注意根据实际类型调整
undertow.ssl.keyStoreType=PKCS12
# 密钥库文件
undertow.ssl.keyStore=demo.pfx
# 密钥库密码
undertow.ssl.keyStorePassword=123456
2
3
4
5
6
7
8
9
10
其中的 "demo.pfx" 即为前面下载的证书文件的文件名,"123456" 即为证书密码,这两个配置根据你下载到的实际内容进行修改。"PKCS12" 这个配置是证书类型,阿里云下载的 tomcat 型证书为 PKCS12,腾迅云可能是 "JKS"
# 3、启动项目
启动项目,通过 "https://申请证书时绑定的域名" 即可访问
# 三、Https 双向认证
如果你的 jfinal undertow 项目需要对客户端进行 ssl 认证,需要使用如下方式进行配置:
UndertowServer.create(YourJFinalConfig.class)
.onStart( builder -> {
builder.setSocketOption(Options.SSL_CLIENT_AUTH_MODE, SslClientAuthMode.REQUESTED);
})
.start();`
2
3
4
5
该方法来自于社区用户的分享:https://jfinal.com/feedback/7758